<?php
/**
 * This file is part of workerman.
 *
 * Licensed under The MIT License
 * For full copyright and license information, please see the MIT-LICENSE.txt
 * Redistributions of files must retain the above copyright notice.
 *
 * @author walkor<walkor@workerman.net>
 * @copyright walkor<walkor@workerman.net>
 * @link http://www.workerman.net/
 * @license http://www.opensource.org/licenses/mit-license.php MIT License
 */

/**
 * 用于检测业务代码死循环或者长时间阻塞等问题
 * 如果发现业务卡死，可以将下面declare打开（去掉//注释），并执行php start.php reload
 * 然后观察一段时间workerman.log看是否有process_timeout异常
 */
//declare(ticks=1);

/**
 * 聊天主逻辑
 * 主要是处理 onMessage onClose 
 */
use \GatewayWorker\Lib\Gateway;

use \Firebase\JWT\JWT;
use \Firebase\JWT\Key;

class Events
{

    /**
     * TODO 
     * //房间id为用户id
     * to_client_id 固定为all, 并且发送数据保存到数据库, 后台客服可以看到消息列表
     */

     private static $key = "lesson";
     private static $alg = "HS256";

    public static $db = null;

    public static $config = [];

    /**
     * 进程启动后初始化数据库连接
     */
    public static function onWorkerStart($worker)
    {
        $config_file = __DIR__.'/../../config.php';
        $config = include_once($config_file);
        if(!$config) {
            throw new \Exception('配置文件错误');
        }
        if(!isset($config['mysql'])) {
            throw new \Exception('数据库配置错误');
        }
        $host = $config['mysql']['host'];
        $port = $config['mysql']['port'];
        $user = $config['mysql']['user'];
        $password = $config['mysql']['password'];
        $db = $config['mysql']['db'];
        self::$db = new \Workerman\MySQL\Connection($host, $port, $user, $password, $db);
    }

    public static function decodeToken($token){
        try {
            $payload = JWT::decode($token, new Key(self::$key, self::$alg));
        } catch(\Exception $e) {
            return false;
        }
        return $payload;
    }

    public static function checkMsg($message_data, $client_id) {
        if(!isset($message_data['token']))
        {
            $new_message = [
                'type'=>$message_data['type'],
                'client_id'=>$client_id,
                'res' => 'No Token',
                'client_name'=> '',
                'time'=>date('Y-m-d H:i:s')
            ];
            Gateway::sendToCurrentClient(json_encode($new_message));
            return false;
        }

        //验证token正确性
        $token = $message_data['token'];
        $payload = self::decodeToken($token);
        if(!$payload) {
            $new_message = [
                'type' => $message_data['type'],
                'client_id' => $client_id,
                'res' => 'Token Error',
                'status' => 'faild',
                'client_name'=> '',
                'time'=>date('Y-m-d H:i:s')
            ];
            Gateway::sendToCurrentClient(json_encode($new_message));
            return false;
        }
        $user = $payload->data;
        if($payload->iss == 'admin') {
            $user->msg_source = 'admin';
            $res = self::$db->select('*')->from('t_admin')->where('id=' . intval($user->id))->row();
            if(!$res) {
                Gateway::sendToCurrentClient(json_encode(['status' => 'faild', 'res' => 'Token Invalid'] ));
                return false;
            }

            if($res['token'] != $token) {
                Gateway::sendToCurrentClient(json_encode(['status' => 'faild', 'res' => 'token expired'] ));
                var_dump($res['token']);
                var_dump($token);
                var_dump($user->id);
                return false;
            }
        } else if($payload->iss == 'member') {

            $res = self::$db->select('*')->from('t_member')->where('id=' . intval($user->id))->row();
            if(!$res) {
                return false;
            }

            if($res['token'] != $token) {
                Gateway::sendToCurrentClient(json_encode(['status' => 'faild', 'res' => 'token error'] ));
                return false;
            }

            $user->msg_source = 'member';
            $user->name = $user->nickname;
        } else {
            return false;
        }

        return $payload->data;
    }


    /**
    * 有消息时
    * @param int $client_id
    * @param mixed $message
    */
    public static function onMessage($client_id, $message)
    {
            // debug
            // echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id session:".json_encode($_SESSION)." onMessage:".$message."\n";
            
            // 客户端传递的是json数据
            $message_data = json_decode($message, true);
            if(!$message_data)
            {
                return ;
            }

            // 根据类型执行不同的业务
            switch($message_data['type'])
            {
                // 客户端回应服务端的心跳
                case 'pong':
                case 'ping':
                    $new_message = [
                        'type' => 'pong',
                    ];
                    //返回用户信息
                    Gateway::sendToCurrentClient(json_encode($new_message));
                    return;
                // 客户端登录 message格式: {type:login, name:xx, room_id:1} ，添加到客户端，广播给所有客户端xx进入聊天室
                case 'login':
                    //判断参数正确性
                    $member = self::checkMsg($message_data, $client_id);
                    if(!$member) {
                        Gateway::closeClient($client_id);
                        return ;
                    }


                    //处理用户消息
                    if($member->msg_source == 'member') {
                        $member_id = $member->id;
                        Gateway::joinGroup($client_id, $member_id);  //member_id 作为房间id
                        $new_message = [
                            'type' => $message_data['type'],
                            'client_id' => $client_id,
                            'status' => 'success',
                            'member_id' => htmlspecialchars($member->id),
                            'client_name' => htmlspecialchars($member->name),
                            'client_avatar' => htmlspecialchars($member->avatar),
                            'msg_source' => $member->msg_source,
                            'time' => date('Y-m-d H:i:s')
                        ];
                        //返回用户信息
                        Gateway::sendToCurrentClient(json_encode($new_message));
                    }

                    //处理后台消息
                    if($member->msg_source == 'admin') {
                        //后台消息必须指定用户id
                        if(!isset($message_data['member_id'])) {
                            $new_message = [
                                'type' => $message_data['type'],
                                'client_id' => $client_id,
                                'client_name' => htmlspecialchars($member->name),
                                'client_avatar' => htmlspecialchars($member->avatar),
                                'status' => 'faild',
                                'res' => 'no member id',
                                'msg_source' => $member->msg_source,
                                'time' => date('Y-m-d H:i:s')
                            ];
                            Gateway::sendToCurrentClient(json_encode($new_message));
                            return;
                        }
                        // $clients_list = Gateway::getClientSessionsByGroup($message_data['member_id']);
                        Gateway::joinGroup($client_id, $message_data['member_id']); 
                        $new_message = [
                            'type' => $message_data['type'],
                            'client_id' => $client_id,
                            'client_name' => htmlspecialchars($member->name),
                            'client_avatar' => htmlspecialchars($member->avatar),
                            'status' => 'success',
                            'msg_source' => $member->msg_source,
                            'time' => date('Y-m-d H:i:s')
                        ];
                        Gateway::sendToCurrentClient(json_encode($new_message));
                    }

                    return ;
                    // if(!isset($message_data['room_id']))
                    // {
                    //     throw new \Exception("\$message_data['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']} \$message:$message");
                    // }
                    
                    // // 把房间号昵称放到session中
                    // $room_id = $message_data['room_id'];
                    // $client_name = htmlspecialchars($message_data['client_name']);
                    // $_SESSION['room_id'] = $room_id;
                    // $_SESSION['client_name'] = $client_name;
                
                    // // 获取房间内所有用户列表 
                    // $clients_list = Gateway::getClientSessionsByGroup($room_id);
                    // foreach($clients_list as $tmp_client_id=>$item)
                    // {
                    //     $clients_list[$tmp_client_id] = $item['client_name'];
                    // }
                    // $clients_list[$client_id] = $client_name;
                    
                    // // 转播给当前房间的所有客户端，xx进入聊天室 message {type:login, client_id:xx, name:xx} 
                    // $new_message = array('type'=>$message_data['type'], 'client_id'=>$client_id, 'client_name'=>htmlspecialchars($client_name), 'time'=>date('Y-m-d H:i:s'));
                    // Gateway::sendToGroup($room_id, json_encode($new_message));
                    // Gateway::joinGroup($client_id, $room_id);
                
                    // // 给当前用户发送用户列表 
                    // $new_message['client_list'] = $clients_list;
                    // Gateway::sendToCurrentClient(json_encode($new_message));
                    // return;
                    
                // 客户端发言 message: {type:say, to_client_id:xx, content:xx}
                case 'say':
                    $member = self::checkMsg($message_data, $client_id);
                    if(!$member) {
                        Gateway::closeClient($client_id);
                        return ;
                    }

                    $msg = strval($message_data['content']);
                    $new_message = [
                        'type'=>'say', 
                        'from_client_id' => $client_id,
                        'from_client_name' => $member->name,
                        'is_img' => intval($message_data['is_img'] ?? 0),
                        // 'to_client_id'=>'all',
                        'content' => nl2br(htmlspecialchars($msg)),
                        'time' => date('Y-m-d H:i:s'),
                    ];

                    //处理用户消息
                    if($member->msg_source == 'member') {
                        $member_id = $member->id;
                        $new_message['member_id'] = $member_id;
                        //保存到消息列表
                        $e = self::$db->select('*')->from('t_chat_session')->where('member_id=' . intval($member->id))->row();
                        if(!$e) {
                            self::$db->insert('t_chat_session')->cols([
                                'member_id' => $member->id,
                                'new_msg_count' => 1,
                                'last_send_time' => time()
                            ])->query();
                        } else {
                            self::$db->update('t_chat_session')
                                ->cols(['new_msg_count', 'last_send_time'])
                                ->where('member_id='.intval($member->id))
                                ->bindValue('new_msg_count', $e['new_msg_count'] + 1)
                                ->bindValue('last_send_time', time())
                                ->query();
                        }

                        //存入历史消息
                        self::$db->insert('t_chat_history')->cols(array(
                            'member_id' => $member->id,
                            'is_img' => intval($message_data['is_img'] ?? 0),
                            'content' => $message_data['content'] ?? '',
                            'send_time' => date('Y-m-d H:i:s')
                        ))->query();
                        
                        return Gateway::sendToGroup($member_id, json_encode($new_message));
                    }

                    //处理后台消息
                    if($member->msg_source == 'admin') {
                        //后台消息必须指定用户id
                        if(!isset($message_data['member_id'])) {
                            $new_message = [
                                'type' => $message_data['type'],
                                'client_id' => $client_id,
                                'client_name' => htmlspecialchars($member->name),
                                'client_avatar' => htmlspecialchars($member->avatar),
                                'status' => 'faild',
                                'res' => 'no member id',
                                'msg_source' => $member->msg_source,
                                'time' => date('Y-m-d H:i:s')
                            ];
                            Gateway::sendToCurrentClient(json_encode($new_message));
                            return;
                        }

                        $admin_id = $member->id;
                        $new_message['admin'] = $admin_id;

                        //存入历史消息
                        self::$db->insert('t_chat_history')->cols(array(
                            'member_id' => $message_data['member_id'],
                            'is_img' => intval($message_data['is_img'] ?? 0),
                            'content' => $message_data['content'] ?? '',
                            'send_time' => date('Y-m-d H:i:s'),
                            'admin_id' => $member->id,
                        ))->query();

                        //清空用户新消息
                        $e = self::$db->select('*')->from('t_chat_session')->where('member_id=' . intval($message_data['member_id']))->row();
                        if($e) {
                            self::$db->update('t_chat_session')
                                ->cols(['new_msg_count', 'last_send_time'])
                                ->where('member_id='.intval($message_data['member_id']))
                                ->bindValue('new_msg_count', 0)
                                ->bindValue('last_send_time', time())
                                ->query();
                        }
                        return Gateway::sendToGroup($message_data['member_id'], json_encode($new_message));
                    }

                    return ;

                    // $new_message = array(
                    //     'type'=>'say', 
                    //     'from_client_id' => $client_id,
                    //     'from_client_name' => $member->name,
                    //     'to_client_id'=>'all',
                    //     'content'=>nl2br(htmlspecialchars($message_data['content'])),
                    //     'time'=>date('Y-m-d H:i:s'),
                    // );
                    // return Gateway::sendToGroup($room_id ,json_encode($new_message));

                    // // 非法请求
                    // if(!isset($_SESSION['room_id']))
                    // {
                    //     throw new \Exception("\$_SESSION['room_id'] not set. client_ip:{$_SERVER['REMOTE_ADDR']}");
                    // }
                    // $room_id = $_SESSION['room_id'];
                    // $client_name = $_SESSION['client_name'];
                    
                    // // 私聊
                    // if($message_data['to_client_id'] != 'all')
                    // {
                    //     $new_message = array(
                    //         'type'=>'say',
                    //         'from_client_id' => $client_id, 
                    //         'from_client_name' =>$client_name,
                    //         'to_client_id'=>$message_data['to_client_id'],
                    //         'content'=>"<b>对你说: </b>".nl2br(htmlspecialchars($message_data['content'])),
                    //         'time'=>date('Y-m-d H:i:s'),
                    //     );
                    //     Gateway::sendToClient($message_data['to_client_id'], json_encode($new_message));
                    //     $new_message['content'] = "<b>你对".htmlspecialchars($message_data['to_client_name'])."说: </b>".nl2br(htmlspecialchars($message_data['content']));
                    //     return Gateway::sendToCurrentClient(json_encode($new_message));
                    // }
                    
                    // $new_message = array(
                    //     'type'=>'say', 
                    //     'from_client_id'=>$client_id,
                    //     'from_client_name' =>$client_name,
                    //     'to_client_id'=>'all',
                    //     'content'=>nl2br(htmlspecialchars($message_data['content'])),
                    //     'time'=>date('Y-m-d H:i:s'),
                    // );
                    // return Gateway::sendToGroup($room_id ,json_encode($new_message));
            }
    }
   
    /**
        * 当客户端断开连接时
        * @param integer $client_id 客户端id
        */
    public static function onClose($client_id)
    {
        // debug
        echo "client:{$_SERVER['REMOTE_ADDR']}:{$_SERVER['REMOTE_PORT']} gateway:{$_SERVER['GATEWAY_ADDR']}:{$_SERVER['GATEWAY_PORT']}  client_id:$client_id onClose:''\n";
        
        // 从房间的客户端列表中删除
        if(isset($_SESSION['room_id']))
        {
            $room_id = $_SESSION['room_id'];
            $new_message = array('type'=>'logout', 'from_client_id'=>$client_id, 'from_client_name'=>$_SESSION['client_name'], 'time'=>date('Y-m-d H:i:s'));
            Gateway::sendToGroup($room_id, json_encode($new_message));
        }
    }
  
}
